package com.wolfpire.workflow.spring.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.jbpm.api.ProcessEngine;
import org.jbpm.api.task.Task;
import org.jbpm.pvm.internal.env.EnvironmentFactory;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.ExecutionImpl;
import org.jbpm.pvm.internal.model.ProcessDefinitionImpl;
import org.jbpm.pvm.internal.model.TransitionImpl;
import org.jbpm.pvm.internal.task.TaskImpl;
import org.springframework.stereotype.Service;

import com.wolfpire.system.common.util.StringUtils;
import com.wolfpire.system.dao.OrgDao;
import com.wolfpire.system.dao.RoleDao;
import com.wolfpire.system.dao.UserDao;
import com.wolfpire.system.model.User;
import com.wolfpire.workflow.dao.JbpmTaskDao;
import com.wolfpire.workflow.dao.NodeDao;
import com.wolfpire.workflow.dao.ProInstanceDao;
import com.wolfpire.workflow.em.ActorType;
import com.wolfpire.workflow.em.OperateType;
import com.wolfpire.workflow.om.JbpmTask;
import com.wolfpire.workflow.om.MyTask;
import com.wolfpire.workflow.om.Node;
import com.wolfpire.workflow.om.NodeActor;
import com.wolfpire.workflow.om.ProInstance;
import com.wolfpire.workflow.spring.JbpmService;
import com.wolfpire.workflow.spring.MyTaskService;
import com.wolfpire.workflow.utils.JbpmUtil;


/**
 * jbpm任务Service
 * @author lihd
 * 
 */
@Service("jbpmTaskService")
public class JbpmTaskService {
	
	@Resource private UserDao userDao;
	
	@Resource private OrgDao orgDao;
	
	@Resource private RoleDao roleDao;
	
	@Resource private JbpmService jbpmService;
	
	@Resource private JbpmTaskDao jbpmTaskDao;
	
	@Resource private ProInstanceDao proInstanceDao;
	
	@Resource private NodeDao nodeDao;
	
	@Resource private ProcessEngine processEngine;
	
	@Resource private MyTaskService myTaskService;
	
	/**
	 * 单步提交执行
	 * @param taskId
	 * @param nextNodeName
	 * @param userIds
	 * @param remarks
	 * @param user
	 * @param operateType
	 * @return
	 */
	public Map<String, Object> subWorkFlowSingle(String taskId,
			String nextNodeName, String userIds, 
			String remarks, User user, String operateType) {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			TaskImpl task = jbpmService.getTask(taskId);
			ExecutionImpl ex = task.getExecution();
			ProcessDefinitionImpl pdi = jbpmService.getPdiByEx(ex);
			Long instanceId = jbpmService.getInstanceIdByTask(task);
			ProInstance pro = this.proInstanceDao.get(instanceId);
			
			Long deploymentId = jbpmService.getDeploymentId(ex);
			Node node = this.nodeDao.getNode(deploymentId, task.getActivityName());
			
			Node nextNode = this.nodeDao.getNode(deploymentId, nextNodeName);
			String execId = task.getExecutionId();
			if (!StringUtils.isBlank(userIds)) {
				//动态分配参与者
				jbpmService.setExecutionVariable(execId, "userIds", userIds);
			}
			if(null != nextNode.getTurnToPromoter() && "1".equals(nextNode.getTurnToPromoter())){
				jbpmService.setExecutionVariable(execId, "userIds", String.valueOf(pro.getUserId()));
			}
			//提交
			if(null != nextNodeName){
				String srcName = ex.getActivityName();
				ActivityImpl act = JbpmUtil.addOutTransition(pdi, srcName,nextNodeName);
				ex.setActivity(act);
				processEngine.getExecutionService().signalExecutionById(ex.getId(), "to "+ nextNodeName);
				JbpmUtil.removeOutTransition(pdi, nextNodeName, srcName);
			}

			this.myTaskService.saveMyTask(task, user, operateType, remarks,	node.getNodeId(), "");
			map.put("success", true);
			map.put("instanceId", instanceId);
			map.put("nextNode", nextNode);
			return map;
		} catch (Exception e) {
			e.printStackTrace();
			map.put("success", false);
			return map;
		}
	}
	
	/**
	 * 单步驳回执行
	 * @param taskId
	 * @param nextNodeName
	 * @param userIds
	 * @param remarks
	 * @param user
	 * @param operateType
	 * @return
	 */
	public Map<String, Object> rejectWorkflowSingle(String taskId, String remarks, User user) {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			TaskImpl task = jbpmService.getTask(taskId);
			ExecutionImpl ex = task.getExecution();
			Long instanceId = jbpmService.getInstanceIdByTask(task);
			Long deploymentId = jbpmService.getDeploymentId(ex);
			Node node = this.nodeDao.getNode(deploymentId, task.getActivityName());
			MyTask lastTask = myTaskService.queryLastTaskInfo(instanceId);
			
			// 驳回节点的任务节点
			@SuppressWarnings("unused")
			String backTaskId = null;
			String backTaskName = null;
			String backTaskUserId = null;
			@SuppressWarnings("unused")
			String backTaskUserName = null;
			// 驳回节点的上一个任务节点
			String backPreTaskId = null;
			
			String lastOperateType = lastTask.getOperateType();
			if (OperateType.PASS.getIndex().equals(lastOperateType)) {
				backTaskId = StringUtils.convert(lastTask.getTaskId());
				backTaskName = StringUtils.convert(lastTask.getTaskName());
				backTaskUserId = StringUtils.convert(lastTask.getTransactorId());
				backTaskUserName = StringUtils.convert(lastTask.getTransactorName());
				backPreTaskId = StringUtils.convert(lastTask.getPreTaskId());
			} else if (OperateType.BACK.getIndex().equals(lastOperateType)) {
				backTaskId = StringUtils.convert(lastTask.getPreTaskId());
				MyTask backTask = this.myTaskService.get(lastTask.getPreTaskId());
				backTaskName = StringUtils.convert(backTask.getTaskName());
				backTaskUserId = StringUtils.convert(backTask.getTransactorId());
				backTaskUserName = StringUtils.convert(backTask.getTransactorName());
				backPreTaskId = StringUtils.convert(backTask.getPreTaskId());
			}
			
			jbpmService.setExecutionVariable(task.getExecutionId(), "userIds", backTaskUserId);
			this.dynamicCreateTransiton(task, task.getActivityName(), backTaskName);
			Node nextNode = this.nodeDao.getNode(deploymentId, backTaskName);

			if (StringUtils.isNotBlank(backPreTaskId)) {
				MyTask backPreTask = myTaskService.get(Long.parseLong(backPreTaskId));
				this.myTaskService.saveMyTask(task, user, OperateType.BACK
						.getIndex().toString(), remarks, node.getNodeId(),
						null, StringUtils.convert(backPreTask.getTaskId()),
						backPreTask.getTaskName(), StringUtils
								.convert(backPreTask.getTransactorId()),
						backPreTask.getTransactorName());
			} else {
				this.myTaskService.saveMyTask(task, user, OperateType.BACK
						.getIndex().toString(), remarks, node.getNodeId(),
						null, null, null, null, null);
			}
			map.put("success", true);
			map.put("instanceId", instanceId);
			map.put("nextNode", nextNode);
			return map;
		} catch (Exception e) {
			e.printStackTrace();
			map.put("success", false);
			return map;
		}
	}
	
	/**
	 * 自由流动态审批(动态转向某个节点)
	 * @param task 当前任务节点
	 * @param destActivityName 源节点名称
	 * @param createTransitionName 目标节点名称
	 */
	public void dynamicCreateTransiton(Task task, String destActivityName, String createTransitionName) {
		// 这里不会影响事物
		EnvironmentImpl envImpl = ((EnvironmentFactory) this.processEngine).openEnvironment();
		try {
			// 动态回退
			ExecutionImpl e = (ExecutionImpl)processEngine.getExecutionService().findExecutionById(task.getExecutionId());
			ActivityImpl currentActivityImpl = e.getActivity();
			ProcessDefinitionImpl processDefinitionImpl = currentActivityImpl.getProcessDefinition();
			// 生成一个transition
			ActivityImpl destActivityImpl = processDefinitionImpl.findActivity(createTransitionName);
			TransitionImpl toApply = currentActivityImpl.createOutgoingTransition();
			toApply.setSource(currentActivityImpl);
			toApply.setDestination(destActivityImpl);
			toApply.setName(createTransitionName);
			processEngine.getTaskService().completeTask(task.getId(), createTransitionName);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			envImpl.close();
		}
	}
	
	public JbpmTask findJbpmTaskByTaskId(String taskId) {
		return jbpmTaskDao.findJbpmTaskByTaskId(taskId);
	}
	
	public Map<String, Object> getData(String instanceId) {
		Map<String, Object> map = new HashMap<String, Object>();
		String taskIds = "";
		String taskNames = "";
		String userIds = "";
		String userNames = "";
		List<JbpmTask> tasks = this.jbpmTaskDao.getJbpmTasks(instanceId);
		for (JbpmTask jt : tasks) {
			taskIds += jt.getDbId() + ",";
			taskNames += jt.getTaskName() + ",";
			// 参与者
			Map<String, Object> participationMap = getOrgUserIdsByTaskId(jt.getDbId());
			userIds += (String) participationMap.get("userIds") + ",";
		}
		
		if(!"".equals(userIds)){
			userIds = userIds.substring(0, userIds.length()-1);
		}
		userNames += (String) getUserOrgName(userIds, "").get("userNames") + ",";
		
		if(!"".equals(taskNames)){
			taskNames = taskNames.substring(0, taskNames.length()-1);
		}
		if(!"".equals(userNames)){
			userNames = userNames.substring(0, userNames.length()-1);
		}
		if(!"".equals(taskIds)){
			taskIds = taskIds.substring(0, taskIds.length()-1);
		}
		
		map.put("WF_USERID", userIds);
		map.put("WF_USERNAME", userNames);
		map.put("WF_DBID_", taskIds);
		map.put("WF_ACTIVITY_NAME_", taskNames);
		return map;
	}

	public Map<String, Object> getOrgUserIdsByTaskId(String taskId) {
	
		Map<String, Object> map = new HashMap<String, Object>();
		List<Map<String, Object>> participationList = jbpmTaskDao.queryParticipationListByTaskId(Long.parseLong(taskId));
		String userIds = "";
		for(Map<String, Object> participation:participationList){
			String type = (String) participation.get("TYPE_");
			if (type.equals(ActorType.USER.getIndex())) {
				if (userIds.indexOf((String) participation.get("USERID_")) == -1) {
					userIds = userIds+ participation.get("USERID_") + ",";
				}
	//			String tempo = (String)participation.get("GROUPID_");
	//			if (!StrUtils.isBlank(tempo) && curOrgIds.indexOf(tempo) == -1) {
	//				curOrgIds += participation.get("GROUPID_") + ",";
	//			}
			}
		}
		
		if(!"".equals(userIds)){
			userIds = userIds.substring(0,userIds.length()-1);
		}
	
		map.put("userIds", userIds);
		return map;
	}
	
	public Map<String, Object> getUserOrgName(String userIds,String orgIds) {
		Map<String, Object> map = new HashMap<String, Object>();
		String userNames = "";
		if(!StringUtils.isBlank(userIds)){
			if(!StringUtils.isBlank(userIds)){

				
				String temp[] = userIds.split(",");
				for (String idStr : temp) {
					User user = this.userDao.get(Long.parseLong(idStr));
					userNames += user.getNickName() + ",";
				}
				if(!"".equals(userNames)){
					userNames = userNames.substring(0, userNames.length()-1);
				}
			
			}
		}
		map.put("userNames", userNames);
		map.put("orgNames", "");
		return map;
	}
	
	public Map<String, Object> getUserOrgName(List<NodeActor> actors) {
		Map<String, Object> map = new HashMap<String, Object>();
		String userNames = "";
		String orgNames = "";
		for(NodeActor actor:actors){
			Long actorId = actor.getActorId();
			String actorType = actor.getActorType();
			if(ActorType.ORG.getIndex().equals(actorType)){
				userNames += orgDao.get(actorId).getName()+",";
			}else if(ActorType.ROLE.getIndex().equals(actorType)){
				userNames += roleDao.get(actorId).getName()+",";
			}else if(ActorType.USER.getIndex().equals(actorType)){
				userNames += userDao.get(actorId).getNickName()+",";
			}
		}
		if(!"".equals(userNames)){
			userNames = userNames.substring(0, userNames.length()-1);
		}
		map.put("userNames", userNames);
		map.put("orgNames", orgNames);
		return map;
	}
}
